package org.truenewx.tnxjee.repo.support;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.*;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.repository.CrudRepository;
import org.truenewx.tnxjee.core.util.BeanUtil;
import org.truenewx.tnxjee.core.util.ClassUtil;
import org.truenewx.tnxjee.model.entity.Entity;
import org.truenewx.tnxjee.model.query.Querying;
import org.truenewx.tnxjee.repo.Repox;

/**
 * 数据访问仓库扩展支持
 *
 * @author jianglei
 */
public abstract class RepoxSupport<T extends Entity> implements Repox<T> {

    @Autowired
    private RepoFactory repoFactory;
    @Autowired
    private DataAccessTemplateFactory accessTemplateFactory;

    /**
     * 获取实体类型<br>
     * 默认实现通过反射机制获取，子类可覆写直接返回具体实体的类型以优化性能
     *
     * @return 实体类型
     */
    protected Class<T> getEntityClass() {
        // 用指定类型的局部变量，以更好地类型转换，直接类型转换返回在IDEA中会编译失败
        Class<T> entityClass = ClassUtil.getActualGenericType(getClass(), 0);
        return entityClass;
    }

    @SuppressWarnings("unchecked")
    protected <R extends CrudRepository<T, K>, K> R getRepository() {
        if (this instanceof CrudRepository) {
            return (R) this;
        }
        return this.repoFactory.getRepository(getEntityClass());
    }

    protected DataAccessTemplate getAccessTemplate() {
        return this.accessTemplateFactory.getDataAccessTemplate(getEntityClass());
    }

    protected Class<?> getPropertyClass(String propertyName) {
        Field field = ClassUtil.findField(getEntityClass(), propertyName);
        return field == null ? null : field.getType();
    }

    protected final List<Object> paramList(Object... array) {
        return new ArrayList<>(Arrays.asList(array));
    }

    protected final Map<String, Object> paramMap(String name, Object value) {
        Map<String, Object> map = new HashMap<>();
        if (value != null) {
            map.put(name, value);
        }
        return map;
    }

    protected final Map<String, Object> paramMap(String name1, Object value1, String name2, Object value2) {
        Map<String, Object> map = new HashMap<>();
        if (value1 != null) {
            map.put(name1, value1);
        }
        if (value2 != null) {
            map.put(name2, value2);
        }
        return map;
    }

    protected final Map<String, Object> paramMap(String name1, Object value1, String name2, Object value2, String name3,
            Object value3) {
        Map<String, Object> map = new HashMap<>();
        if (value1 != null) {
            map.put(name1, value1);
        }
        if (value2 != null) {
            map.put(name2, value2);
        }
        if (value3 != null) {
            map.put(name3, value3);
        }
        return map;
    }

    protected final Map<String, Object> paramMap(Object model, String... excludedProperties) {
        Map<String, Object> params = new LinkedHashMap<>();
        BeanUtil.loopProperties(model, (name, value) -> {
            if (!ArrayUtils.contains(excludedProperties, name) && isValidParamValue(value)) {
                params.put(name, value);
            }
        }, Querying.BASE_PROPERTY_NAMES);
        return params;
    }

    private boolean isValidParamValue(Object value) {
        if (value instanceof CharSequence) {
            return StringUtils.isNotBlank((String) value);
        } else if (value != null) {
            // 不加入空数组
            if (value.getClass().isArray() && Array.getLength(value) == 0) {
                return false;
            }
            // 不加入空集合
            if (value instanceof Collection && ((Collection<?>) value).isEmpty()) {
                return false;
            }
            // 不加入空映射集
            if (value instanceof Map && ((Map<?, ?>) value).isEmpty()) {
                return false;
            }
            return true;
        }
        return false;
    }

}
